﻿/*
 *  DFUtil - a utility for creating and implementing blueprints in Dwarf Fortress.
 *  
 *  Copyright (C) 2009  Katharine Gillis
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
*/

using System;
using System.Drawing;
using System.Windows.Forms;

namespace DFUtil
{
    /// <summary>
    /// DFUtil main form.
    /// </summary>
    public partial class Form1 : Form, IObserver
    {
        #region Variables

        private DFAdapter _df;
        private string _imagesPath;
        private bool _status = false;
        private bool _updatingPhaseList = false;
        private bool _updatingFloorList = false;

        #endregion

        #region Properties

        public DFAdapter DFAdapter
        {
            get { return _df; }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Main form for DFUtil.
        /// </summary>
        public Form1()
        {
            InitializeComponent();
            _df = new DFAdapter();
            _df.Attach(this);
            _imagesPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName) + "\\Images\\";
            cmbPhases.SelectedIndexChanged += new EventHandler(cmbPhases_SelectedIndexChanged);
            cmbFloors.SelectedIndexChanged += new EventHandler(cmbFloors_SelectedIndexChanged);
        }

        #endregion

        #region IObserver Members

        /// <summary>
        /// Is called when a change occurs in one of the observable subjects the main form is attached to.
        /// </summary>
        /// <param name="sender">The observable subject that has changed.</param>
        /// <param name="response">The response from the subject.</param>
        public void Update(Subject sender, object response)
        {
            if ((DFAdapter)sender == _df)
            {
                if ((bool)response)
                {
                    if (this.InvokeRequired)
                    {
                        BeginInvoke(new MethodInvoker(delegate() { updateDFStatus(true); }));
                    }
                    else
                        updateDFStatus(true);
                }
                else
                {
                    if (this.InvokeRequired)
                    {
                        BeginInvoke(new MethodInvoker(delegate() { updateDFStatus(false); }));
                    }
                    else
                        updateDFStatus(false);
                }
            }
        }

        #endregion

        #region Private members

        // Handles the DF status variable and image representation.
        private void updateDFStatus(bool status)
        {
            if (_status != status)
            {
                if (status)
                    imgDFStatus.Image = Image.FromFile(_imagesPath + "c.gif");
                else
                    imgDFStatus.Image = Image.FromFile(_imagesPath + "dc.gif");
                _status = status;
            }
        }

        // Updates the form title to include the file name and the active phase name.
        private void UpdateTitle()
        {
            Text = "DFUtil - " + blueprintEditor1.FileName + " - " + (blueprintEditor1.PhaseName != null ? blueprintEditor1.PhaseName : "Phase " + (blueprintEditor1.ActivePhase + 1));
        }

        // Updates the phase drop down list items.
        private void UpdatePhaseList()
        {
            _updatingPhaseList = true;
            cmbPhases.ComboBox.DataSource = blueprintEditor1.GetPhaseNames();
            cmbPhases.SelectedIndex = blueprintEditor1.ActivePhase;
            UpdateFloorList();
            _updatingPhaseList = false;
        }

        // Updates the floor drop down list items.
        private void UpdateFloorList()
        {
            _updatingFloorList = true;
            cmbFloors.ComboBox.DataSource = blueprintEditor1.GetFloorNames();
            cmbFloors.SelectedIndex = blueprintEditor1.ActiveFloor;
            _updatingFloorList = false;

        }

        #endregion

        #region Form event callback functions

        // Handles the Load event.
        private void Form1_Load(object sender, EventArgs e)
        {
            UpdateTitle();
            UpdatePhaseList();
        }

        #endregion

        #region Control event callback functions

        // Handles the exit menu item click.
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        // Handles the configure menu item click.
        private void configureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgConfig dlgConfig = new dlgConfig();
            dlgConfig.CallingForm = this;
            dlgConfig.ShowDialog();
        }

        // Handles the New Phase -> Designate menu item click.
        private void designateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgBeforeAfter dlgBeforeAfter = new dlgBeforeAfter();
            dlgBeforeAfter.ItemType = "phase";
            if (dlgBeforeAfter.ShowDialog() == DialogResult.OK)
            {
                if (dlgBeforeAfter.Before)
                    blueprintEditor1.AddPhase(PhaseType.Designate, blueprintEditor1.ActivePhase);
                else
                    blueprintEditor1.AddPhase(PhaseType.Designate, blueprintEditor1.ActivePhase + 1);
                UpdateTitle();
                UpdatePhaseList();
            }
        }
        
        // Handles the index changed event of the phases combo box.
        private void cmbPhases_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_updatingPhaseList)
            {
                blueprintEditor1.ActivePhase = cmbPhases.SelectedIndex;
                UpdateTitle();
                UpdateFloorList();
            }
        }

        // Handles the Rename Phase menu item click.
        private void renToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgRenamePhase dlgRenamePhase = new dlgRenamePhase();
            if (dlgRenamePhase.ShowDialog() == DialogResult.OK)
            {
                blueprintEditor1.PhaseName = dlgRenamePhase.PhaseName;
                UpdateTitle();
                UpdatePhaseList();
            }
        }

        // Handles the Remove Phase menu item click.
        private void removePhaseToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!blueprintEditor1.RemovePhase(blueprintEditor1.ActivePhase))
            {
                dlgError dlgError = new dlgError();
                dlgError.ErrorMsg = "You cannot remove the only phase in the blueprint.";
                dlgError.ShowDialog();
            }
            else
            {
                UpdateTitle();
                UpdatePhaseList();
            }
        }

        // Handles the index changed event of the floors combo box.
        private void cmbFloors_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_updatingFloorList)
            {
                blueprintEditor1.ActiveFloor = cmbFloors.SelectedIndex;
            }
        }

        // Handles the New Floor menu item click.
        private void newFloorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            dlgBeforeAfter dlgBeforeAfter = new dlgBeforeAfter();
            dlgBeforeAfter.ItemType = "phase";
            if (dlgBeforeAfter.ShowDialog() == DialogResult.OK)
            {
                if (dlgBeforeAfter.Before)
                    blueprintEditor1.AddFloor(blueprintEditor1.ActiveFloor);
                else
                    blueprintEditor1.AddFloor(blueprintEditor1.ActiveFloor + 1);
                UpdateFloorList();
            }
        }

        // Handles the Remove Floor menu item click.
        private void removeFloorToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (!blueprintEditor1.RemoveFloor(blueprintEditor1.ActiveFloor))
            {
                dlgError dlgError = new dlgError();
                dlgError.ErrorMsg = "You cannot remove the only floor in the phase.";
                dlgError.ShowDialog();
            }
            else
                UpdateFloorList();
        }

        // Handles the Starting Point button being toggled.
        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            blueprintEditor1.ToggleSetStartingPoint();
        }

        #endregion
    }
}
